home *** CD-ROM | disk | FTP | other *** search
- // bake.C -- code for an Entropy DSO shadeop implementing the "bake" function.
- //
- // The function prototype for bake is:
- // void bake (string file, float s, float t, TYPE val)
- // where TYPE may be any of {float, color, point, vector, normal}.
- // The bake function writes (s,t,val) tuples to the given filename,
- // which may later be processed in a variety of ways.
- //
- // "bake" is (c) Copyright 2002 by Larry Gritz. It was developed
- // for the SIGGRAPH 2002, course #16, "RenderMan in Production."
- // This code may be modified and/or redistributed, but only if it
- // contains the original attribution above and a reference to the
- // SIGGRAPH 2002 course notes in which it appears.
-
-
- #include <stdio.h>
- #include <string.h>
- #include <malloc.h>
- #include <map>
- #include <string>
- #include <pthread.h>
-
-
- //////////////////////////////////////////////////////////////////////////
- // Declarations -- this is all boilerplate and is necessary for the
- // shader compiler and renderer to understand what functions are
- // implemented in this DSO and what arguments they take.
- //////////////////////////////////////////////////////////////////////////
-
- #include "dsoshadeop.h"
-
- extern "C" {
-
- EXPORT int protocol_version = DS_PROTOCOL_VERSION;
-
- EXPORT DS_DispatchTableEntry bake_shadeops[] = {
- { "void bake_f (string, float, float, float)", "bake_init", "bake_done" },
- { "void bake_3 (string, float, float, color)", "bake_init", "bake_done" },
- { "void bake_3 (string, float, float, point)", "bake_init", "bake_done" },
- { "void bake_3 (string, float, float, vector)", "bake_init", "bake_done" },
- { "void bake_3 (string, float, float, normal)", "bake_init", "bake_done" },
- { "", "", "" }
- };
-
- EXPORT void *bake_init (int, void *);
- EXPORT void bake_done (void *data);
- EXPORT int bake_f (void *data, int nargs, void **args);
- EXPORT int bake_3 (void *data, int nargs, void **args);
-
- }; /* extern "C" */
-
-
-
- //////////////////////////////////////////////////////////////////////////
- // Implementation
- //////////////////////////////////////////////////////////////////////////
-
- const int batchsize = 10240; // elements to buffer before writing
-
- // Make sure we're thread-safe on those file writes
- static pthread_mutex_t mutex;
- static pthread_once_t once_block = PTHREAD_ONCE_INIT;
-
- static void ptinitonce (void)
- {
- pthread_mutex_init (&mutex, NULL);
- }
-
-
-
- class BakingChannel {
- // A "BakingChannel" is the buffer for a single baking output file.
- // We buffer up samples until "batchsize" has been accepted, then
- // write them all at once. This keeps us from constantly accessing
- // the disk. Note that we are careful to use a mutex to keep
- // simultaneous multithreaded writes from clobbering each other.
- public:
- // Constructors
- BakingChannel (void) : filename(NULL), data(NULL), buffered(0) { }
- BakingChannel (const char *_filename, int _elsize) {
- init (_filename, _elsize);
- }
-
- // Initialize - allocate memory, etc.
- void init (const char *_filename, int _elsize) {
- elsize = _elsize+2;
- buffered = 0;
- data = new float [elsize*batchsize];
- filename = strdup (_filename);
- pthread_once (&once_block, ptinitonce);
- }
-
- // Destructor: write buffered output, close file, deallocate
- ~BakingChannel () {
- writedata();
- free (filename);
- delete [] data;
- }
-
- // Add one more data item
- void moredata (float s, float t, float *newdata) {
- if (buffered >= batchsize)
- writedata();
- float *f = data + elsize*buffered;
- f[0] = s;
- f[1] = t;
- for (int j = 2; j < elsize; ++j)
- f[j] = newdata[j-2];
- ++buffered;
- }
-
- private:
- int elsize; // element size (e.g., 3 for colors)
- int buffered; // how many elements are currently buffered
- float *data; // pointer to the allocated buffer (new'ed)
- char *filename; // pointer to filename (strdup'ed)
-
- // Write any buffered data to the file
- void writedata (void) {
- if (buffered > 0 && filename != NULL) {
- pthread_mutex_lock (&mutex);
- FILE *file = fopen (filename, "a");
- float *f = data;
- for (int i = 0; i < buffered; ++i, f += elsize) {
- for (int j = 0; j < elsize; ++j)
- fprintf (file, "%g ", f[j]);
- fprintf (file, "\n");
- }
- fclose (file);
- pthread_mutex_unlock (&mutex);
- }
- buffered = 0;
- }
- };
-
-
-
- typedef std::map<std::string, BakingChannel> BakingData;
- // We keep a mapping of strings (filenames) to bake data (BakingChannel).
-
-
- // DSO shadeop Initilizer -- allocate and return a new BakingData
- EXPORT void *bake_init (int, void *)
- {
- BakingData *bd = new BakingData;
- return (void *)bd;
- }
-
-
-
- // DSO shadeop cleanup -- destroy the BakingData
- EXPORT void bake_done (void *data)
- {
- BakingData *bd = (BakingData *) data;
- delete bd; // Will destroy bd, and in turn all its BakingChannel's
- }
-
-
-
- // Workhorse routine -- look up the channel name, add a new BakingChannel
- // if it doesn't exist, add one point's data to the channel.
- void
- bake (BakingData *bd, const std::string &name,
- float s, float t, int elsize, float *data)
- {
- BakingData::iterator found = bd->find (name);
- if (found == bd->end()) {
- // This named map doesn't yet exist
- (*bd)[name] = BakingChannel();
- found = bd->find (name);
- BakingChannel &bc (found->second);
- bc.init (name.c_str(), elsize);
- bc.moredata (s, t, data);
- } else {
- BakingChannel &bc (found->second);
- bc.moredata (s, t, data);
- }
- }
-
-
-
- // DSO shadeop for baking a float -- just call bake with appropriate args
- EXPORT int bake_f (void *data, int nargs, void **args)
- {
- BakingData *bd = (BakingData *) data;
- std::string name (*((char **) args[1]));
- float *s = (float *) args[2];
- float *t = (float *) args[3];
- float *bakedata = (float *) args[4];
- bake (bd, name, *s, *t, 1, bakedata);
- return 0;
- }
-
-
- // DSO shadeop for baking a triple -- just call bake with appropriate args
- EXPORT int bake_3 (void *data, int nargs, void **args)
- {
- BakingData *bd = (BakingData *) data;
- char **name = (char **) args[1];
- float *s = (float *) args[2];
- float *t = (float *) args[3];
- float *bakedata = (float *) args[4];
- bake (bd, *name, *s, *t, 3, bakedata);
- return 0;
- }
-